package bitmap

import (
	"bytes"
	"compress/gzip"
	"encoding/base64"
	"github.com/RoaringBitmap/roaring/v2/roaring64"
	"io"
	"os"
)

func encodeData(ba *roaring64.Bitmap) ([]byte, error) {

	b, err := ba.ToBytes()
	if err != nil {
		return nil, err
	}

	return compressData(b)
}

func compressData(input []byte) ([]byte, error) {
	var compressedBuffer bytes.Buffer
	gzipWriter := gzip.NewWriter(&compressedBuffer)
	_, err := gzipWriter.Write(input)
	if err != nil {
		return nil, err
	}
	_ = gzipWriter.Close()
	return compressedBuffer.Bytes(), nil
}

func decodeData(byteData []byte) (*roaring64.Bitmap, error) {

	b1, err := decompressData(byteData)
	if err != nil {
		return nil, err
	}

	b := roaring64.NewBitmap()
	_, _ = b.ReadFrom(bytes.NewReader(b1))
	return b, nil
}
func decompressData(compressedData []byte) ([]byte, error) {
	gzipReader, err := gzip.NewReader(bytes.NewReader(compressedData))
	if err != nil {
		return nil, err
	}
	defer gzipReader.Close()
	decompressedData, err := io.ReadAll(gzipReader)
	if err != nil {
		return nil, err
	}
	return decompressedData, nil
}

func readFile(fileName string) (*roaring64.Bitmap, error) {

	fileBody, err := os.ReadFile(fileName)
	if err != nil {
		return nil, err
	}

	return decodeData(fileBody)
}

func writeFile(ba *roaring64.Bitmap, fileName string) error {

	b, _ := encodeData(ba)
	return os.WriteFile(fileName, b, 0644)
}

func ToString[T uint64 | int64 | int | uint](datas ...T) (string, error) {

	var (
		ba = roaring64.NewBitmap()
	)
	for _, v := range datas {
		ba.Add(uint64(v))
	}

	b, _ := encodeData(ba)
	return base64.StdEncoding.EncodeToString(b), nil
}

func FromString(data string) (*roaring64.Bitmap, error) {

	bb, err := base64.StdEncoding.DecodeString(data)
	if err != nil {
		return nil, err
	}
	return decodeData(bb)
}
